home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / wgdb-42.lha / wgdb-4.2 / gdb / nindy-share / Onindy.c < prev    next >
C/C++ Source or Header  |  1992-09-11  |  32KB  |  1,144 lines

  1. /*****************************************************************************
  2.  *         Copyright (c) 1990, Intel Corporation
  3.  *
  4.  * Intel hereby grants you permission to copy, modify, and 
  5.  * distribute this software and its documentation.  Intel grants
  6.  * this permission provided that the above copyright notice 
  7.  * appears in all copies and that both the copyright notice and
  8.  * this permission notice appear in supporting documentation.  In
  9.  * addition, Intel grants this permission provided that you
  10.  * prominently mark as not part of the original any modifications
  11.  * made to this software or documentation, and that the name of 
  12.  * Intel Corporation not be used in advertising or publicity 
  13.  * pertaining to distribution of the software or the documentation 
  14.  * without specific, written prior permission.  
  15.  *
  16.  * Intel Corporation does not warrant, guarantee or make any 
  17.  * representations regarding the use of, or the results of the use
  18.  * of, the software and documentation in terms of correctness, 
  19.  * accuracy, reliability, currentness, or otherwise; and you rely
  20.  * on the software, documentation and results solely at your own risk.
  21.  *****************************************************************************/
  22.  
  23. static char rcsid[] =
  24.     "Id: Onindy.c,v 1.1.1.1 1991/03/28 16:20:43 rich Exp $";
  25.  
  26. /******************************************************************************
  27.  *
  28.  *             NINDY INTERFACE ROUTINES
  29.  *
  30.  * This version of the NINDY interface routines supports NINDY versions
  31.  * 2.13 and older.  The older versions used a hex communication protocol,
  32.  * instead of the (faster) current binary protocol.   These routines have
  33.  * been renamed by prepending the letter 'O' to their names, to avoid
  34.  * conflict with the current version.  The old versions are kept only for
  35.  * backward compatibility, and well disappear in a future release.
  36.  *
  37.  ******************************************************************************/
  38.  
  39. #include <stdio.h>
  40. #include <sys/ioctl.h>
  41. #include <sys/types.h>    /* Needed by file.h on Sys V */
  42. #include <sys/file.h>
  43. #include <signal.h>
  44. #include <sys/stat.h>
  45. #include <fcntl.h>    /* Needed on Sys V */
  46. #include "ttycntl.h"
  47. #include "block_io.h"
  48. #include "wait.h"
  49. #include "env.h"
  50.  
  51.  
  52. #ifdef USG
  53. #    include <unistd.h>
  54. #    include "sysv.h"
  55. #else    /* BSD */
  56. #    include "string.h"
  57. #endif
  58.  
  59. #ifndef TRUE
  60. #define TRUE    1
  61. #endif
  62.  
  63. #ifndef FALSE
  64. #define FALSE    0
  65. #endif
  66.  
  67. #ifndef ERROR
  68. #define ERROR    -1
  69. #endif
  70.  
  71. #define REGISTER_BYTES ((36*4) + (4*8))
  72.  
  73. extern char *malloc();
  74. extern void free ();
  75.  
  76. static int quiet;    /* TRUE => stifle unnecessary messages */
  77. static int nindy_fd;    /* File descriptor of tty connected to 960/NINDY board*/
  78. static OninStrGet();
  79.  
  80.         /****************************
  81.          *                          *
  82.          *  MISCELLANEOUS UTILTIES  *
  83.          *                          *
  84.          ****************************/
  85.  
  86.  
  87. /******************************************************************************
  88.  * fromhex:
  89.  *    Convert a hex ascii digit h to a binary integer
  90.  ******************************************************************************/
  91. static
  92. int
  93. fromhex( h )
  94.     int h;
  95. {
  96.     if (h >= '0' && h <= '9'){
  97.         h -= '0';
  98.     } else if (h >= 'a' && h <= 'f'){
  99.         h -= 'a' - 10;
  100.     } else {
  101.         h = 0;
  102.     }
  103.     return (h & 0xff);
  104. }
  105.  
  106.  
  107. /******************************************************************************
  108.  * hexbin:
  109.  *    Convert a string of ASCII hex digits to a string of binary bytes.
  110.  ******************************************************************************/
  111. static
  112. hexbin( n, hexp, binp )
  113.     int n;        /* Number of bytes to convert (twice this many digits)*/
  114.     char *hexp;        /* Get hex from here        */
  115.     char *binp;        /* Put binary here        */
  116. {
  117.     while ( n-- ){
  118.         *binp++ = (fromhex(*hexp) << 4) | fromhex(*(hexp+1));
  119.         hexp += 2;
  120.     }
  121. }
  122.  
  123.  
  124. /******************************************************************************
  125.  * binhex:
  126.  *    Convert a string of binary bytes to a string of ASCII hex digits
  127.  ******************************************************************************/
  128. static
  129. binhex( n, binp, hexp )
  130.     int n;              /* Number of bytes to convert   */
  131.     char *binp;         /* Get binary from here         */
  132.     char *hexp;         /* Place hex here               */
  133. {
  134.     static char tohex[] = "0123456789abcdef";
  135.  
  136.         while ( n-- ){
  137.                 *hexp++ = tohex[ (*binp >> 4) & 0xf ];
  138.                 *hexp++ = tohex[ *binp & 0xf ];
  139.                 binp++;
  140.         }
  141. }
  142.  
  143. /******************************************************************************
  144.  * byte_order:
  145.  *    If the host byte order is different from 960 byte order (i.e., the
  146.  *    host is big-endian), reverse the bytes in the passed value;  otherwise,
  147.  *    return the passed value unchanged.
  148.  *
  149.  ******************************************************************************/
  150. static
  151. long
  152. byte_order( n )
  153.     long n;
  154. {
  155.     long rev;
  156.     int i;
  157.     static short test = 0x1234;
  158.  
  159.     if (*((char *) &test) == 0x12) {
  160.         /*
  161.          * Big-endian host, swap the bytes.
  162.          */
  163.         rev = 0;
  164.         for ( i = 0; i < sizeof(n); i++ ){
  165.             rev <<= 8;
  166.             rev |= n & 0xff;
  167.             n >>= 8;
  168.         }
  169.         n = rev;
  170.     }
  171.     return n;
  172. }
  173.  
  174. /******************************************************************************
  175.  * say:
  176.  *    This is a printf that takes at most two arguments (in addition to the
  177.  *    format string) and that outputs nothing if verbose output has been
  178.  *    suppressed.
  179.  ******************************************************************************/
  180. static
  181. say( fmt, arg1, arg2 )
  182.     char *fmt;
  183.     int arg1, arg2;
  184. {
  185.     if ( !quiet ){
  186.         printf( fmt, arg1, arg2 );
  187.         fflush( stdout );
  188.     }
  189. }
  190.  
  191. /******************************************************************************
  192.  * exists:
  193.  *    Creates a full pathname by concatenating up to three name components
  194.  *    onto a specified base name; optionally looks up the base name as a
  195.  *    runtime environment variable;  and checks to see if the file or
  196.  *    directory specified by the pathname actually exists.
  197.  *
  198.  *    Returns:  the full pathname if it exists, NULL otherwise.
  199.  *        (returned pathname is in malloc'd memory and must be freed
  200.  *        by caller).
  201.  *****************************************************************************/
  202. static
  203. char *
  204. exists( base, c1, c2, c3, env )
  205.     char *base;        /* Base directory of path */
  206.     char *c1, *c2, *c3;    /* Components (subdirectories and/or file name) to be
  207.              *    appended onto the base directory name.  One or
  208.              *    more may be omitted by passing NULL pointers.
  209.              */
  210.     int env;        /* If 1, '*base' is the name of an environment variable
  211.              *    to be examined for the base directory name;
  212.              *    otherwise, '*base' is the actual name of the
  213.              *    base directory.
  214.              */
  215. {
  216.     struct stat buf;/* For call to 'stat' -- never examined */
  217.     char *path;    /* Pointer to full pathname (malloc'd memory) */
  218.     int len;    /* Length of full pathname (incl. terminator) */
  219.     extern char *getenv();
  220.  
  221.  
  222.     if ( env ){
  223.         base = getenv( base );
  224.         if ( base == NULL ){
  225.             return NULL;
  226.         }
  227.     }
  228.  
  229.     len = strlen(base) + 4;
  230.             /* +4 for terminator and "/" before each component */
  231.     if ( c1 != NULL ){
  232.         len += strlen(c1);
  233.     }
  234.     if ( c2 != NULL ){
  235.         len += strlen(c2);
  236.     }
  237.     if ( c3 != NULL ){
  238.         len += strlen(c3);
  239.     }
  240.  
  241.     path = malloc( len );
  242.  
  243.     strcpy( path, base );
  244.     if ( c1 != NULL ){
  245.         strcat( path, "/" );
  246.         strcat( path, c1 );
  247.         if ( c2 != NULL ){
  248.             strcat( path, "/" );
  249.             strcat( path, c2 );
  250.             if ( c3 != NULL ){
  251.                 strcat( path, "/" );
  252.                 strcat( path, c3 );
  253.             }
  254.         }
  255.     }
  256.  
  257.     if ( stat(path,&buf) != 0 ){
  258.         free( path );
  259.         path = NULL;
  260.     }
  261.     return path;
  262. }
  263.  
  264.         /*****************************
  265.          *                           *
  266.          *  LOW-LEVEL COMMUNICATION  *
  267.          *                           *
  268.          *****************************/
  269.  
  270. /******************************************************************************
  271.  * readchar:
  272.  *    Wait for a character to come in on the NINDY tty, and return it.
  273.  ******************************************************************************/
  274. static
  275. readchar()
  276. {
  277.     unsigned char c;
  278.  
  279.     while (read(nindy_fd,&c,1) != 1){
  280.         ;
  281.     }
  282.     return c;
  283. }
  284.  
  285.  
  286. /******************************************************************************
  287.  * getpkt:
  288.  *    Read a packet from a remote NINDY, with error checking, and return
  289.  *    it in the indicated buffer.
  290.  ******************************************************************************/
  291. static
  292. getpkt (buf)
  293.      char *buf;
  294. {
  295.     unsigned char recv;    /* Checksum received        */
  296.     unsigned char csum;    /* Checksum calculated        */
  297.     char *bp;        /* Poointer into the buffer    */
  298.     int c;
  299.  
  300.     while (1){
  301.         csum = 0;
  302.         bp = buf;
  303.         while ( (c = readchar()) != '#' ){
  304.             *bp++ = c;
  305.             csum += c;
  306.         }
  307.         *bp = 0;
  308.  
  309.         recv = fromhex(readchar()) << 4;
  310.         recv |= fromhex(readchar());
  311.         if ( csum == recv ){
  312.             break;
  313.         }
  314.     
  315.         fprintf(stderr,
  316.             "Bad checksum (recv=0x%02x; calc=0x%02x); retrying\r\n",
  317.                                 recv, csum );
  318.         write (nindy_fd, "-", 1);
  319.     }
  320.  
  321.     write (nindy_fd, "+", 1);
  322. }
  323.  
  324.  
  325. /******************************************************************************
  326.  * putpkt:
  327.  *    Checksum and send a gdb command to a remote NINDY, and wait for
  328.  *    positive acknowledgement.
  329.  *
  330.  ******************************************************************************/
  331. static
  332. putpkt( cmd )
  333.     char *cmd;    /* Command to be sent, without lead ^P (\020)
  334.          * or trailing checksum
  335.          */
  336. {
  337.     char ack;    /* Response received from NINDY        */
  338.     char checksum[4];
  339.     char *p;
  340.     unsigned int s;
  341.     char resend;
  342.  
  343.     for ( s='\020', p=cmd; *p; p++ ){
  344.         s += *p;
  345.     }
  346.     sprintf( checksum, "#%02x",  s & 0xff );
  347.  
  348.     /* Send checksummed message over and over until we get a positive ack
  349.      */
  350.     resend = TRUE;
  351.     do {
  352.         if ( resend ){
  353.             write( nindy_fd, "\020", 1 );
  354.             write( nindy_fd, cmd, strlen(cmd) );
  355.             write( nindy_fd, checksum, strlen(checksum) );
  356.         }
  357.         if  ( read( nindy_fd, &ack, 1 ) != 1 ){
  358.             fprintf(stderr,"oink\n");
  359.         }
  360.         if ( ack == '-' ){
  361.             fprintf( stderr, "Remote NAK, resending\r\n" );
  362.             resend = TRUE;
  363.         } else if ( ack != '+' ){
  364.             fprintf( stderr, "Bad ACK, ignored: <%c>\r\n", ack );
  365.             resend = FALSE;
  366.         }
  367.     } while ( ack != '+' );
  368. }
  369.  
  370.  
  371.  
  372. /******************************************************************************
  373.  * send:
  374.  *    Send a message to a remote NINDY and return the reply in the same
  375.  *    buffer (clobbers the input message).  Check for error responses
  376.  *    as indicated by the second argument.
  377.  *
  378.  ******************************************************************************/
  379. static
  380. send( buf, ack_required )
  381.     char *buf;        /* Message to be sent to NINDY; replaced by
  382.              *    NINDY's response.
  383.              */
  384.     int ack_required;    /* TRUE means NINDY's response MUST be either "X00" (no
  385.              *    error) or an error code "Xnn".
  386.              * FALSE means the it's OK as long as it doesn't
  387.              *    begin with "Xnn".
  388.              */
  389. {
  390.     int errnum;
  391.     static char *errmsg[] = {
  392.         "",                        /* X00 */
  393.         "Buffer overflow",                /* X01 */
  394.         "Unknown command",                /* X02 */
  395.         "Wrong amount of data to load register(s)",    /* X03 */
  396.         "Missing command argument(s)",            /* X04 */
  397.         "Odd number of digits sent to load memory",    /* X05 */
  398.         "Unknown register name",            /* X06 */
  399.         "No such memory segment",            /* X07 */
  400.         "No breakpoint available",            /* X08 */
  401.         "Can't set requested baud rate",        /* X09 */
  402.     };
  403. #    define NUMERRS    ( sizeof(errmsg) / sizeof(errmsg[0]) )
  404.  
  405.     static char err0[] = "NINDY failed to acknowledge command: <%s>\r\n";
  406.     static char err1[] = "Unknown error response from NINDY: <%s>\r\n";
  407.     static char err2[] = "Error response %s from NINDY: %s\r\n";
  408.  
  409.     putpkt (buf);
  410.     getpkt (buf);
  411.  
  412.     if ( buf[0] != 'X' ){
  413.         if ( ack_required ){
  414.             fprintf( stderr, err0, buf );
  415.             abort();
  416.         }
  417.  
  418.     } else if ( strcmp(buf,"X00") ){
  419.         sscanf( &buf[1], "%x", &errnum );
  420.         if ( errnum > NUMERRS ){
  421.             fprintf( stderr, err1, buf );
  422.         } else{
  423.             fprintf( stderr, err2, buf, errmsg[errnum] );
  424.         }
  425.         abort();
  426.     }
  427. }
  428.  
  429.         /************************
  430.          *                      *
  431.          *  BAUD RATE ROUTINES  *
  432.          *                      *
  433.          ************************/
  434.  
  435. /* Table of baudrates known to be acceptable to NINDY.  Each baud rate
  436.  * appears both as character string and as a Unix baud rate constant.
  437.  */
  438. struct baudrate {
  439.     char *string;
  440.     int rate;
  441. };
  442.  
  443. static struct baudrate baudtab[] = {
  444.      "1200", B1200,
  445.      "2400", B2400,
  446.      "4800", B4800,
  447.      "9600", B9600,
  448.     "19200", B19200,
  449.     "38400", B38400,
  450.     NULL,    0        /* End of table */
  451. };
  452.  
  453.  
  454. /******************************************************************************
  455.  * parse_baudrate:
  456.  *    Look up the passed baud rate in the baudrate table.  If found, change
  457.  *    our internal record of the current baud rate, but don't do anything
  458.  *    about the tty just now.
  459.  *
  460.  *    Return pointer to baudrate structure on success, NULL on failure.
  461.  ******************************************************************************/
  462. static
  463. struct baudrate *
  464. parse_baudrate(s)
  465.     char *s;    /* Desired baud rate, as an ASCII (decimal) string */
  466. {
  467.     int i;
  468.  
  469.     for ( i=0; baudtab[i].string != NULL; i++ ){
  470.         if ( !strcmp(baudtab[i].string,s) ){
  471.             return &baudtab[i];
  472.         }
  473.     }
  474.     return NULL;
  475. }
  476.  
  477. /******************************************************************************
  478.  * try_baudrate:
  479.  *    Try speaking to NINDY via the specified file descriptor at the
  480.  *    specified baudrate.  Assume success it we can send an empty command
  481.  *    with a bogus checksum and receive a NAK (response of '-') back within
  482.  *    one second.
  483.  *
  484.  *    Return 1 on success, 0 on failure.
  485.  ******************************************************************************/
  486.  
  487. static int saw_alarm;
  488.  
  489. static void
  490. alarm_handler()
  491. {
  492.     saw_alarm = 1;
  493. }
  494.  
  495. static int
  496. try_baudrate( fd, brp )
  497.     int fd;
  498.     struct baudrate *brp;
  499. {
  500.     TTY_STRUCT tty;
  501.     char c;
  502.     int n;
  503.     void (*old_alarm)();    /* Save alarm signal handler here on entry */
  504.     
  505.  
  506.     /* Set specified baud rate and flush all pending input */
  507.     ioctl( fd, TIOCGETP, &tty );
  508.     TTY_REMOTE( tty, brp->rate );
  509.     ioctl( fd, TIOCSETP, &tty );
  510.     tty_flush( fd );
  511.  
  512.     /* Send bogus command */
  513.     write( fd, "\020#00", 4 );
  514.  
  515.     /* Wait until reponse comes back or one second passes */
  516.     old_alarm = signal( SIGALRM,alarm_handler );
  517.     saw_alarm = 0;
  518.     alarm(1);
  519.     do {
  520.         n = 1;
  521.         TTY_NBREAD(fd,n,&c);
  522.     } while ( n<=0 && !saw_alarm );
  523.  
  524.     /* Turn off alarm */
  525.     alarm(0);
  526.     signal( SIGALRM,old_alarm );
  527.  
  528.     /* Did we get a '-' back ? */
  529.     if ( (n > 0) && (c == '-') ){
  530.         return 1;
  531.     }
  532.     return 0;
  533. }
  534.  
  535. /******************************************************************************
  536.  * autobaud:
  537.  *    Get NINDY talking over the specified file descriptor at the specified
  538.  *    baud rate.  First see if NINDY's already talking at 'baudrate'.  If
  539.  *    not, run through all the legal baudrates in 'baudtab' until one works,
  540.  *    and then tell NINDY to talk at 'baudrate' instead.
  541.  ******************************************************************************/
  542. static
  543. autobaud( fd, brp )
  544.     int fd;
  545.     struct baudrate *brp;
  546. {
  547.     int i;
  548.     TTY_STRUCT tty;
  549.  
  550.  
  551.     say("NINDY at wrong baud rate? Trying to autobaud...\n");
  552.     i = 0;
  553.     while ( 1 ){
  554.         say( "\r%s...   ", baudtab[i].string );
  555.         if ( try_baudrate(fd,&baudtab[i]) ){
  556.             break;
  557.         }
  558.         if ( baudtab[++i].string == NULL ){
  559.             /* End of table -- wraparound */
  560.             i = 0;
  561.             say("\nAutobaud failed. Trying again...\n");
  562.         }
  563.     }
  564.  
  565.     /* Found NINDY's current baud rate;  now change it.
  566.      */
  567.     say("Changing NINDY baudrate to %s\n", brp->string);
  568.     OninBaud( brp->string );
  569.  
  570.     /* Change our baud rate back to rate to which we just set NINDY.
  571.      */
  572.     ioctl( fd, TIOCGETP, &tty );
  573.     TTY_REMOTE( tty, brp->rate );
  574.     ioctl( fd, TIOCSETP, &tty );
  575. }
  576.  
  577.         /**********************************
  578.          *                  *
  579.          *   NINDY INTERFACE ROUTINES      *
  580.          *                                  *
  581.          * ninConnect *MUST* be the first *
  582.          * one of these routines called.  *
  583.          **********************************/
  584.  
  585.  
  586. /******************************************************************************
  587.  * ninBaud:
  588.  *    Ask NINDY to change the baud rate on its serial port.
  589.  *    Assumes we know the baud rate at which NINDY's currently talking.
  590.  ******************************************************************************/
  591. OninBaud( baudrate )
  592.     char *baudrate;    /* Desired baud rate, as a string of ASCII decimal
  593.              * digits.
  594.              */
  595. {
  596.     char buf[100];        /* Message buffer    */
  597.     char *p;        /* Pointer into buffer    */
  598.     unsigned char csum;    /* Calculated checksum    */
  599.  
  600.     tty_flush( nindy_fd );
  601.  
  602.     /* Can't use putpkt() because after the baudrate change
  603.      * NINDY's ack/nak will look like gibberish.
  604.      */
  605.     for ( p=baudrate, csum=020+'z'; *p; p++ ){
  606.         csum += *p;
  607.     }
  608.     sprintf( buf, "\020z%s#%02x", baudrate, csum );
  609.     write( nindy_fd, buf, strlen(buf) );
  610. }
  611.  
  612.  
  613. /******************************************************************************
  614.  * ninBptDel:
  615.  *    Ask NINDY to delete the specified type of *hardware* breakpoint at
  616.  *    the specified address.  If the 'addr' is -1, all breakpoints of
  617.  *    the specified type are deleted.
  618.  ******************************************************************************/
  619. OninBptDel( addr, data )
  620.     long addr;    /* Address in 960 memory    */
  621.     int data;    /* '1' => data bkpt, '0' => instruction breakpoint */
  622. {
  623.     char buf[100];
  624.  
  625.     if ( addr == -1 ){
  626.         sprintf( buf, "b%c", data ? '1' : '0' );
  627.     } else {
  628.         sprintf( buf, "b%c%x", data ? '1' : '0', addr );
  629.     }
  630.     return send( buf, FALSE );
  631. }
  632.  
  633.  
  634. /******************************************************************************
  635.  * ninBptSet:
  636.  *    Ask NINDY to set the specified type of *hardware* breakpoint at
  637.  *    the specified address.
  638.  ******************************************************************************/
  639. OninBptSet( addr, data )
  640.     long addr;    /* Address in 960 memory    */
  641.     int data;    /* '1' => data bkpt, '0' => instruction breakpoint */
  642. {
  643.     char buf[100];
  644.  
  645.     sprintf( buf, "B%c%x", data ? '1' : '0', addr );
  646.     return send( buf, FALSE );
  647. }
  648.  
  649.  
  650. /******************************************************************************
  651.  * ninConnect:
  652.  *    Open the specified tty.  Get communications working at the specified
  653.  *    Flush any pending I/O on the tty.
  654.  *
  655.  *    Return the file descriptor, or -1 on failure.
  656.  ******************************************************************************/
  657. int
  658. OninConnect( name, baudrate, brk, silent )
  659.     char *name;        /* "/dev/ttyXX" to be opened            */
  660.     char *baudrate;/* baud rate: a string of ascii decimal digits (eg,"9600")*/
  661.     int brk;        /* 1 => send break to tty first thing after opening it*/
  662.     int silent;        /* 1 => stifle unnecessary messages when talking to 
  663.              *    this tty.
  664.              */
  665. {
  666.     int i;
  667.     char *p;
  668.     struct baudrate *brp;
  669.  
  670.     /* We will try each of the following paths when trying to open the tty
  671.      */
  672.     static char *prefix[] = { "", "/dev/", "/dev/tty", NULL };
  673.  
  674.     quiet = silent;        /* Make global to this file */
  675.  
  676.     for ( i=0; prefix[i] != NULL; i++ ){
  677.         p = malloc(strlen(prefix[i]) + strlen(name) + 1 );
  678.         strcpy( p, prefix[i] );
  679.         strcat( p, name );
  680.         nindy_fd = open(p,O_RDWR);
  681.         if ( nindy_fd >= 0 ){
  682. #ifdef TIOCEXCL
  683.             /* Exclusive use mode (hp9000 does not support it) */
  684.             ioctl(nindy_fd,TIOCEXCL,NULL);
  685. #endif
  686.             if ( brk ){
  687.                 send_break( nindy_fd );
  688.             }
  689.  
  690.             brp = parse_baudrate( baudrate );
  691.             if ( brp == NULL ){
  692.                 say("Illegal baudrate %s ignored; using 9600\n",
  693.                                 baudrate);
  694.                 brp = parse_baudrate( "9600" );
  695.             }
  696.  
  697.             if ( !try_baudrate(nindy_fd,brp) ){
  698.                 autobaud(nindy_fd,brp);
  699.             }
  700.             tty_flush( nindy_fd );
  701.             say( "Connected to %s\n", p );
  702.             free(p);
  703.             break;
  704.         }
  705.         free(p);
  706.     }
  707.     return nindy_fd;
  708. }
  709.  
  710.  
  711.  
  712. /******************************************************************************
  713.  * ninDownload:
  714.  *    Ask NINDY to start up it's COFF downloader. Invoke 'sx' to perform
  715.  *    the XMODEM download from the host end.
  716.  *
  717.  *    Return 1 on success, 0 on failure.
  718.  ******************************************************************************/
  719.  
  720. #define XMODEM    "sx"    /* Name of xmodem transfer utility    */
  721.  
  722. int
  723. OninDownload( fn, quiet )
  724.     char *fn;        /* Stripped copy of object file            */
  725.     int quiet;
  726. {
  727.     char *p;    /* Pointer to full pathname of sx utility    */
  728.     int success;    /* Return value                    */
  729.     int pid;    /* Process ID of xmodem transfer utility    */
  730.     WAITTYPE w;    /* xmodem transfer completion status        */
  731.     char buf[200];
  732.  
  733.  
  734.     /* Make sure the xmodem utility is findable.  This must be done before
  735.      * we start up the NINDY end of the download (NINDY will hang if we
  736.      * don't complete the download).
  737.      */
  738.     if ( ((p = exists("G960BIN",XMODEM,NULL,NULL,1)) == NULL)
  739.     &&   ((p = exists("G960BASE","bin",XMODEM, NULL,1)) == NULL)
  740. #ifdef HOST
  741.     &&   ((p = exists(DEFAULT_BASE,HOST,"bin",XMODEM,0)) == NULL)
  742. #endif
  743.                                       ){
  744.  
  745.         fprintf(stderr,"Can't find '%s' download utility\n",XMODEM);
  746.         fprintf(stderr,"Check env variables G960BIN and G960BASE\n");
  747.         return 0;
  748.     }
  749.  
  750.     if ( !quiet ){
  751.         printf( "Downloading %s\n", fn );
  752.     }
  753.  
  754.     /* Reset NINDY,  wait until "reset-complete" ack,
  755.      * and start up the NINDY end of the download.
  756.      */
  757.     OninReset();
  758.     putpkt( "D" );
  759.  
  760.     /* Invoke x-modem transfer, a separate process.  DON'T
  761.      * use system() to do this -- under system V Unix, the
  762.      * redirection of stdin/stdout causes the nindy tty to
  763.      * lose all the transmission parameters we've set up.
  764.      */
  765.     success = 0;
  766.  
  767.     pid = fork();
  768.     if ( pid == -1 ){
  769.         perror( "Can't fork process:" );
  770.  
  771.     } else if ( pid == 0 ){        /* CHILD */
  772.         dup2( nindy_fd, 0 );    /* Redirect stdin */
  773.         dup2( nindy_fd, 1 );    /* Redirect stout */
  774.         if ( quiet ){
  775.             execl( p, p, "-q", fn, (char*)0 );
  776.         } else {
  777.             execl( p, p, fn, (char*)0 );
  778.         }
  779.         /* Don't get here unless execl fails */
  780.         sprintf( buf, "Can't exec %s", p );
  781.         perror( buf );
  782.  
  783.     } else {            /* PARENT */
  784.         if ( wait(&w) == -1 ){
  785.             perror( "Wait failed" );
  786.         } else if (WIFEXITED(w) && (WEXITSTATUS(w) == 0)){
  787.             success = 1;
  788.         }
  789.     }
  790.     return success;
  791. }
  792.  
  793.  
  794. /******************************************************************************
  795.  * ninGdbExit:
  796.  *    Ask NINDY to leave GDB mode and print a NINDY prompt.
  797.  *    Since it'll no longer be in GDB mode, don't wait for a response.
  798.  ******************************************************************************/
  799. OninGdbExit()
  800. {
  801.         putpkt( "E" );
  802. }
  803.  
  804.  
  805. /******************************************************************************
  806.  * ninGo:
  807.  *    Ask NINDY to start or continue execution of an application program
  808.  *    in it's memory at the current ip.
  809.  ******************************************************************************/
  810. OninGo( step_flag )
  811.     int step_flag;    /* 1 => run in single-step mode */
  812. {
  813.     putpkt( step_flag ? "s" : "c" );
  814. }
  815.  
  816.  
  817. /******************************************************************************
  818.  * ninMemGet:
  819.  *    Read a string of bytes from NINDY's address space (960 memory).
  820.  ******************************************************************************/
  821. OninMemGet(ninaddr, hostaddr, len)
  822.      long ninaddr;    /* Source address, in the 960 memory space    */
  823.      char *hostaddr;    /* Destination address, in our memory space    */
  824.      int len;        /* Number of bytes to read            */
  825. {
  826.     char buf[2*BUFSIZE+20];    /* Buffer: hex in, binary out        */
  827.     int cnt;        /* Number of bytes in next transfer    */
  828.  
  829.     for ( ; len > 0; len -= BUFSIZE ){
  830.         cnt = len > BUFSIZE ? BUFSIZE : len;
  831.  
  832.         sprintf( buf, "m%x,%x", ninaddr, cnt );
  833.         send( buf, FALSE );
  834.         hexbin( cnt, buf, hostaddr );
  835.  
  836.         ninaddr += cnt;
  837.         hostaddr += cnt;
  838.     }
  839. }
  840.  
  841.  
  842. /******************************************************************************
  843.  * ninMemPut:
  844.  *    Write a string of bytes into NINDY's address space (960 memory).
  845.  ******************************************************************************/
  846. OninMemPut( destaddr, srcaddr, len )
  847.      long destaddr;    /* Destination address, in NINDY memory space    */
  848.      char *srcaddr;    /* Source address, in our memory space        */
  849.      int len;        /* Number of bytes to write            */
  850. {
  851.     char buf[2*BUFSIZE+20];    /* Buffer: binary in, hex out        */
  852.     char *p;        /* Pointer into buffer            */
  853.     int cnt;        /* Number of bytes in next transfer    */
  854.  
  855.     for ( ; len > 0; len -= BUFSIZE ){
  856.         cnt = len > BUFSIZE ? BUFSIZE : len;
  857.  
  858.         sprintf( buf, "M%x,", destaddr );
  859.         p = buf + strlen(buf);
  860.         binhex( cnt, srcaddr, p );
  861.         *(p+(2*cnt)) = '\0';
  862.         send( buf, TRUE );
  863.  
  864.         srcaddr += cnt;
  865.         destaddr += cnt;
  866.     }
  867. }
  868.  
  869. /******************************************************************************
  870.  * ninRegGet:
  871.  *    Retrieve the contents of a 960 register, and return them as a long
  872.  *    in host byte order.
  873.  *
  874.  *    THIS ROUTINE CAN ONLY BE USED TO READ THE LOCAL, GLOBAL, AND
  875.  *    ip/ac/pc/tc REGISTERS.
  876.  *
  877.  ******************************************************************************/
  878. long
  879. OninRegGet( regname )
  880.     char *regname;    /* Register name recognized by NINDY, subject to the
  881.              * above limitations.
  882.              */
  883. {
  884.     char buf[200];
  885.     long val;
  886.  
  887.     sprintf( buf, "u%s", regname );
  888.     send( buf, FALSE );
  889.     hexbin( 4, buf, (char *)&val );
  890.     return byte_order(val);
  891. }
  892.  
  893. /******************************************************************************
  894.  * ninRegPut:
  895.  *    Set the contents of a 960 register.
  896.  *
  897.  *    THIS ROUTINE CAN ONLY BE USED TO SET THE LOCAL, GLOBAL, AND
  898.  *    ip/ac/pc/tc REGISTERS.
  899.  *
  900.  ******************************************************************************/
  901. OninRegPut( regname, val )
  902.     char *regname;    /* Register name recognized by NINDY, subject to the
  903.              * above limitations.
  904.              */
  905.     long val;        /* New contents of register, in host byte-order    */
  906. {
  907.     char buf[200];
  908.  
  909.     sprintf( buf, "U%s,%08x", regname, byte_order(val) );
  910.     send( buf, TRUE );
  911. }
  912.  
  913. /******************************************************************************
  914.  * ninRegsGet:
  915.  *    Get a dump of the contents of the entire 960 register set.  The
  916.  *    individual registers appear in the dump in the following order:
  917.  *
  918.  *        pfp  sp   rip  r3   r4   r5   r6   r7 
  919.  *        r8   r9   r10  r11  r12  r13  r14  r15 
  920.  *        g0   g1   g2   g3   g4   g5   g6   g7 
  921.  *        g8   g9   g10  g11  g12  g13  g14  fp 
  922.  *        pc   ac   ip   tc   fp0  fp1  fp2  fp3
  923.  *
  924.  *    Each individual register comprises exactly 4 bytes, except for
  925.  *    fp0-fp3, which are 8 bytes.
  926.  *
  927.  * WARNING:
  928.  *    Each register value is in 960 (little-endian) byte order.
  929.  *
  930.  ******************************************************************************/
  931. OninRegsGet( regp )
  932.     char *regp;        /* Where to place the register dump */
  933. {
  934.     char buf[(2*REGISTER_BYTES)+10];   /* Registers in ASCII hex */
  935.  
  936.     strcpy( buf, "r" );
  937.     send( buf, FALSE );
  938.     hexbin( REGISTER_BYTES, buf, regp );
  939. }
  940.  
  941. /******************************************************************************
  942.  * ninRegsPut:
  943.  *    Initialize the entire 960 register set to a specified set of values.
  944.  *    The format of the register value data should be the same as that
  945.  *    returned by ninRegsGet.
  946.  *
  947.  * WARNING:
  948.  *    Each register value should be in 960 (little-endian) byte order.
  949.  *
  950.  ******************************************************************************/
  951. OninRegsPut( regp )
  952.     char *regp;        /* Pointer to desired values of registers */
  953. {
  954.     char buf[(2*REGISTER_BYTES)+10];   /* Registers in ASCII hex */
  955.  
  956.     buf[0] = 'R';
  957.     binhex( REGISTER_BYTES, regp, buf+1 );
  958.     buf[ (2*REGISTER_BYTES)+1 ] = '\0';
  959.  
  960.     send( buf, TRUE );
  961. }
  962.  
  963.  
  964. /******************************************************************************
  965.  * ninReset:
  966.  *      Ask NINDY to perform a soft reset; wait for the reset to complete.
  967.  ******************************************************************************/
  968. OninReset()
  969. {
  970.  
  971.     putpkt( "X" );
  972.     while ( readchar() != '+' ){
  973.         ;
  974.     }
  975. }
  976.  
  977.  
  978. /******************************************************************************
  979.  * ninSrq:
  980.  *    Assume NINDY has stopped execution of the 960 application program in
  981.  *    order to process a host service request (srq).  Ask NINDY for the
  982.  *    srq arguments, perform the requested service, and send an "srq
  983.  *    complete" message so NINDY will return control to the application.
  984.  *
  985.  ******************************************************************************/
  986. OninSrq()
  987. {
  988.     char buf[BUFSIZE];
  989.     int retcode;
  990.     unsigned char srqnum;
  991.     char *p;
  992.     char *argp;
  993.     int nargs;
  994.     int arg[MAX_SRQ_ARGS];
  995.  
  996.  
  997.     /* Get srq number and arguments
  998.      */
  999.     strcpy( buf, "!" );
  1000.     send( buf, FALSE );
  1001.     hexbin( 1, buf, (char *)&srqnum );
  1002.  
  1003.     /* Set up array of pointers the each of the individual
  1004.      * comma-separated args
  1005.      */
  1006.     nargs=0;
  1007.     argp = p = buf+2;
  1008.         while ( 1 ){
  1009.                 while ( *p != ',' && *p != '\0' ){
  1010.                         p++;
  1011.                 }
  1012.                 sscanf( argp, "%x", &arg[nargs++] );
  1013.                 if ( *p == '\0' || nargs == MAX_SRQ_ARGS ){
  1014.                         break;
  1015.                 }
  1016.                 argp = ++p;
  1017.         }
  1018.  
  1019.     /* Process Srq
  1020.      */
  1021.     switch( srqnum ){
  1022.     case BS_CLOSE:
  1023.         /* args: file descriptor */
  1024.         if ( arg[0] > 2 ){
  1025.             retcode = close( arg[0] );
  1026.         } else {
  1027.             retcode = 0;
  1028.         }
  1029.         break;
  1030.     case BS_CREAT:
  1031.         /* args: filename, mode */
  1032.         OninStrGet( arg[0], buf );
  1033.         retcode = creat(buf,arg[1]);
  1034.         break;
  1035.     case BS_OPEN:
  1036.         /* args: filename, flags, mode */
  1037.         OninStrGet( arg[0], buf );
  1038.         retcode = open(buf,arg[1],arg[2]);
  1039.         break;
  1040.     case BS_READ:
  1041.         /* args: file descriptor, buffer, count */
  1042.         retcode = read(arg[0],buf,arg[2]);
  1043.         if ( retcode > 0 ){
  1044.             OninMemPut( arg[1], buf, retcode );
  1045.         }
  1046.         break;
  1047.     case BS_SEEK:
  1048.         /* args: file descriptor, offset, whence */
  1049.         retcode = lseek(arg[0],arg[1],arg[2]);
  1050.         break;
  1051.     case BS_WRITE:
  1052.         /* args: file descriptor, buffer, count */
  1053.         OninMemGet( arg[1], buf, arg[2] );
  1054.         retcode = write(arg[0],buf,arg[2]);
  1055.         break;
  1056.     default:
  1057.         retcode = ERROR;
  1058.         break;
  1059.     }
  1060.  
  1061.     /* Tell NINDY to continue
  1062.      */
  1063.     sprintf( buf, "e%x", retcode );
  1064.     send( buf, TRUE );
  1065. }
  1066.  
  1067.  
  1068. /******************************************************************************
  1069.  * ninStopWhy:
  1070.  *    Assume the application program has stopped (i.e., a DLE was received
  1071.  *    from NINDY).  Ask NINDY for status information describing the
  1072.  *    reason for the halt.
  1073.  *
  1074.  *    Returns a non-zero value if the user program has exited, 0 otherwise.
  1075.  *    Also returns the following information, through passed pointers:
  1076.  *           - why: an exit code if program the exited; otherwise the reason
  1077.  *            why the program halted (see stop.h for values).
  1078.  *        - contents of register ip (little-endian byte order)
  1079.  *        - contents of register sp (little-endian byte order)
  1080.  *        - contents of register fp (little-endian byte order)
  1081.  ******************************************************************************/
  1082. char
  1083. OninStopWhy( whyp, ipp, fpp, spp )
  1084.     char *whyp;    /* Return the 'why' code through this pointer    */
  1085.     char *ipp;    /* Return contents of register ip through this pointer    */
  1086.     char *fpp;    /* Return contents of register fp through this pointer    */
  1087.     char *spp;    /* Return contents of register sp through this pointer    */
  1088. {
  1089.     char buf[30];
  1090.     char stop_exit;
  1091.  
  1092.     strcpy( buf, "?" );
  1093.     send( buf, FALSE );
  1094.     hexbin( 1, buf, &stop_exit );
  1095.     hexbin( 1, buf+2, whyp );
  1096.     hexbin( 4, buf+4, ipp );
  1097.     hexbin( 4, buf+12, fpp );
  1098.     hexbin( 4, buf+20, spp );
  1099.     return stop_exit;
  1100. }
  1101.  
  1102. /******************************************************************************
  1103.  * ninStrGet:
  1104.  *    Read a '\0'-terminated string of data out of the 960 memory space.
  1105.  *
  1106.  ******************************************************************************/
  1107. static
  1108. OninStrGet( ninaddr, hostaddr )
  1109.      unsigned long ninaddr;    /* Address of string in NINDY memory space */
  1110.      char *hostaddr;        /* Address of the buffer to which string should
  1111.                  *    be copied.
  1112.                  */
  1113. {
  1114.     char buf[BUFSIZE];    /* String as 2 ASCII hex digits per byte */
  1115.     int numchars;        /* Length of string in bytes.        */
  1116.  
  1117.     sprintf( buf, "\"%x", ninaddr );
  1118.     send( buf, FALSE );
  1119.     numchars = strlen(buf)/2;
  1120.     hexbin( numchars, buf, hostaddr );
  1121.     hostaddr[numchars] = '\0';
  1122. }
  1123.  
  1124. /******************************************************************************
  1125.  * ninVersion:
  1126.  *    Ask NINDY for version information about itself.
  1127.  *    The information is sent as an ascii string in the form "x.xx,<arch>",
  1128.  *    where,
  1129.  *        x.xx    is the version number
  1130.  *        <arch>    is the processor architecture: "KA", "KB", "MC", "CA" *
  1131.  *
  1132.  ******************************************************************************/
  1133. int
  1134. OninVersion( p )
  1135.      char *p;        /* Where to place version string */
  1136. {
  1137.     char buf[BUFSIZE];
  1138.  
  1139.     strcpy( buf, "v" );
  1140.     send( buf, FALSE );
  1141.     strcpy( p, buf );
  1142.     return strlen( buf );
  1143. }
  1144.